using System;
using System.IO;
using System.Security;
using System.Xml;
using System.Xml.Serialization;
using BusinessLogic.Connectivity.Entities;
using BusinessLogic.Cryptography;
using BusinessLogic.Mappers;
using DataAccess.Services;

namespace BusinessLogic.Managers.Processing
{
	internal abstract class DocumentProcessorBase<DocType> : IDocumentProcessor where DocType : class
	{
		public void Process(DocumentEnvelope envelope, IServiceManager serviceManager)
		{
			object document = GetDocument(envelope.DocXML, typeof (DocType));
			CheckDocumentSignature(envelope, envelope.SenderId, serviceManager);

			ExceptionCatcher.Execute(delegate 
			                         	{
			                         		Process((DocType) document, serviceManager);
			                         		envelope.Status = DocumentEnvelopeStatus.Processed;
			                         	}
			                         , document, serviceManager, envelope);
		}

		protected abstract void Process(DocType document, IServiceManager serviceManager);
		protected abstract ProcessingExceptionCatcherBase ExceptionCatcher { get; }

		private static object GetDocument(string xml, Type type)
		{
			var serializer = new XmlSerializer(type);
			
			using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
			{
				try
				{
					if (!serializer.CanDeserialize(reader))
					{
						throw new DocumentFormatException();
					}
				}
				catch
				{
					throw new DocumentFormatException();
				}

				return serializer.Deserialize(reader);
			}
		}

		private static void CheckDocumentSignature(DocumentEnvelope envelope, int clientId, IServiceManager serviceManager)
		{
			string publicKey = MapperFactory.GetUserMapper(serviceManager).GetUserPublicKey(clientId);

			if(!RSADigitalSignatureManager.VerifySginature(envelope.DocXML, envelope.Signature, publicKey))
			{
				throw new SecurityException("Received document is inconsistent: either provided signature or the document itself is corrupted.");
			}
		}
	}
}